#ifndef TIEC_FOUNDATION_H
#define TIEC_FOUNDATION_H

#include "macro.h"
#include "data.h"
#include "file.h"

namespace NS_TIEC {
  static WString kSourceExtension = L"t";
  static WString kIrExtension = L"tir";
  static WString kBytecodeExtension = L"tcs";

  /// 输入文件类型定义
  enum struct SourceKind {
    /// 源代码
    kSyntax = 0,
    /// IR中间代码
    kIr = 1,
    /// 字节码
    kBytecode = 2
  };

  /// 编译器输入文件抽象接口
  class Source {
  public:
    /// 获取输入文件的名称
    /// \return 文件名
    virtual WString getName() = 0;

    /// 获取文件最后修改时间
    /// \return 时间戳
    virtual UInt64 lastModified() = 0;

    /// 读取文件内容
    /// \return 文件的全部内容
    virtual WString readContent() = 0;

    /// 获取URI
    /// \return URI
    virtual Uri getUri() = 0;

    /// 获取文件路径
    /// \return 文件绝对路径
    virtual WString getPath() = 0;

    /// 添加子源文件
    virtual void addChildSource(const PTR<Source>& source) = 0;

    /// 获取输入源关联子输入源合并编译
    /// \return 子输入源集合
    virtual const List<PTR<Source>> childSources() = 0;

    /// 获取文件类型
    /// \return 当前文件的类型
    virtual SourceKind getKind() = 0;
  };

  /// 本地文件输入源
  class FileSource : public Source {
  public:
    explicit FileSource(const File& file);

    WString getName() override;

    UInt64 lastModified() override;

    WString readContent() override;

    Uri getUri() override;

    WString getPath() override;

    void addChildSource(const PTR<Source>& source) override;

    const List<PTR<Source>> childSources() override;

    SourceKind getKind() override;
  private:
    File file_;
    List<PTR<Source>> child_sources_;
  };

  /// 文本Source
  class WStringSource : public Source {
  public:
    explicit WStringSource(const WString& name, const WString& content, const Uri& uri);

    WString getName() override;

    UInt64 lastModified() override;

    WString readContent() override;

    Uri getUri() override;

    WString getPath() override;

    void addChildSource(const std::shared_ptr<Source> &source) override;

    const List<std::shared_ptr<Source>> childSources() override;

    SourceKind getKind() override;
  private:
    WString name_;
    WString content_;
    Uri uri_;
  };

  /// PTR<TiecodeSource>的hash计算函数
  struct SourcePtrHash {
    const size_t operator()(const PTR<Source>& source) const {
      return source->getUri().hash();
    }
  };
  /// PTR<TiecodeSource>的值比对函数
  struct SourcePtrEqual {
    const size_t operator()(const PTR<Source>& a, const PTR<Source>& b) const {
      return a->getUri() == b->getUri();
    }
  };

  /// 位置描述
  struct Position {
    size_t line;
    size_t column;
    size_t index;

    /// 将当前Position加上指定长度得到新的position
    /// \param length 长度
    /// \return 新的Position
    Position plusColumn(size_t length) const;

  };

  /// 范围描述
  struct Range {
    Position start;
    Position end;
  };

  /// 语法树位置范围描述
  struct Origin {
    Int64 source_id {-1};
    Range range;
  };

  /// 名称接口定义
  class Name {
  public:
    /// 转换为wstring
    virtual WString asWString() = 0;

    /// 转换为string
    virtual String asString() = 0;

    /// 转换为C字符串（内存安全）
    virtual UPTR<const char[]> asCString() = 0;

    /// 获取字符长度
    /// \return 总字符长度
    virtual size_t length() = 0;

    /// 查找某个字符在Name中的位置
    /// \param ch 字符
    virtual size_t indexOf(const wchar_t* ch) = 0;

    /// 反向查找某个字符在Name中的位置
    /// \param ch 字符
    virtual size_t lastIndexOf(const wchar_t* ch) = 0;

    /// 判断内容是否和某个宽字符串相同
    /// \param text 文本
    /// \return 相同返回true，否则false
    virtual bool contentSameAs(const WString& text) = 0;

    /// 判断内容是否和某个字符串相同
    /// \param text 文本
    /// \return 相同返回true，否则false
    virtual bool contentSameAs(const String& text) = 0;

    /// 计算Name的哈希值
    virtual size_t hash() = 0;
  };

  class StringName: public Name {
  public:
    StringName(const WString& str);

    WString asWString() override;

    String asString() override;

    UPTR<const char[]> asCString() override;

    size_t length() override;

    size_t indexOf(const wchar_t* ch) override;

    size_t lastIndexOf(const wchar_t* ch) override;

    bool contentSameAs(const WString& text) override;

    bool contentSameAs(const String& text) override;

    size_t hash() override;
  private:
    WString str_;
  };

  /// PTR<Name>的哈希函数
  struct NamePtrHash {
    bool operator()(const PTR<Name>& name) const {
      return name->hash();
    }
  };

  /// PTR<Name>的值比对函数
  struct NamePtrEqual {
    bool operator()(const PTR<Name>& a, const PTR<Name>& b) const {
      return a == b;
    }
  };

  /// 日志等级
  enum struct LogLevel {
    kLevelDebug = 0,
    kLevelInfo = 1,
    kLevelWarning = 2,
    kLevelError = 3,
    kLevelFatal = 4,
  };

  /// 诊断信息
  struct Diagnostic {
    String uri;
    Range range;
    String key;
    String message;
    LogLevel level;

    Diagnostic();

    explicit Diagnostic(const String& message);

    Diagnostic(const String& message, LogLevel level);

    Diagnostic(const String& uri, const Range& range, const String& message, const String& key);

    Diagnostic(const String& uri, const Range& range, const String& key, const String& message, LogLevel level);
  };

  /// 编译器任务类型
  enum struct TaskKind {
    /// 语法树解析阶段
    kParse = 0,
    /// 符号表填充阶段
    kEnter,
    /// 语法树标注阶段
    kAttribute,
    /// 最终输出阶段
    kFinal
  };

  /// 将 TaskKind 转换为可读String
  /// @param kind TaskKind
  const char* taskKindToString(const TaskKind& kind);
}
#endif //TIEC_FOUNDATION_H
